home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / C Internet Config / IC Resource ƒ / IC Link In.c < prev    next >
Encoding:
Text File  |  1995-12-06  |  37.0 KB  |  1,244 lines  |  [TEXT/SPM ]

  1. ICRChooseConfig(ICRRecord* inst){
  2.     OSErr err=noErr;
  3.     FSSpec config;
  4.     
  5.     if (inst->perm!=icNoPerm)
  6.         return paramErr;
  7.     
  8.     err=CanInteract();
  9.     
  10.     if (err==noErr){
  11.         err=GetFile(inst,&config);
  12.     }
  13.     
  14.     if (err==noErr){
  15.         err=ICRSpecifyConfigFile(inst,&config);
  16.     }
  17.     
  18.     return err;
  19. }
  20.  
  21. ICError ICRChooseNewConfig(ICRRecord* inst){
  22.     OSErr err=noErr;
  23.     FSSpec config;
  24.     
  25.     if (inst->perm!=icNoPerm)
  26.         return paramErr;
  27.     
  28.     err=CanInteract();
  29.     
  30.     if (err==noErr)
  31.         err=PutFile(inst,&config);
  32.     
  33.     if (err==noErr){
  34.         HDelete(config.vRefNum,config.parID,config.name);
  35.         err=HCreate(config.vRefNum,config.parID,config.name,kICCreator,kICFileType);
  36.     }
  37.     
  38.     if (err==noErr)
  39.         err=ICRSpecifyConfigFile(inst,&config);
  40.     
  41.     return err;
  42. }
  43.  
  44. ICError ICRGetConfigName(ICRRecord* inst,Boolean longname,StringPtr name){
  45.     OSErr err=noErr;
  46.     
  47.     if (!inst->have_config_file)
  48.         return paramErr;
  49.     
  50.     if (!longname){
  51.         BlockMoveData(inst->config_file.name,name,inst->config_file.name[0]+1);
  52.         err=noErr;
  53.     } else {
  54.         err=FSSpecToFullPath(&(inst->config_file),name);
  55.     }
  56.     
  57.     return err;
  58. }
  59.  
  60. ICError ICRGetConfigReference(ICRRecord* inst,ICConfigRefHandle ref){
  61.     ICError err=noErr;
  62.     ICConfigRef header;
  63.     long loe;
  64.     
  65.     if (!inst->have_config_file)
  66.         return paramErr;
  67.     
  68.     if (ref==(ICConfigRefHandle)0)
  69.         return paramErr;
  70.     
  71.     err=FSSpecToICFileSpec(&(inst->config_file),(ICFileSpecHandle)ref);
  72.     
  73.     if (err==noErr){
  74.         header.manufacturer=kICOurManufacturer;
  75.         loe=Munger((Handle)ref,0,(Ptr)0,0,&header,sizeof(ICConfigRef));
  76.         err=MemError();
  77.     }
  78.     
  79.     if (err!=noErr)
  80.         SetHandleSize((Handle)ref,0);
  81.     
  82.     return err;
  83. }
  84.  
  85. ICError ICRSetConfigReference(ICRRecord* inst,ICConfigRefHandle ref,long flags){
  86.     ICError err;
  87.     ICFileSpecHandle filespec;
  88.     long loe;
  89.     FSSpec fs;
  90.     
  91.     if (inst->perm!=icNoPerm)
  92.         return paramErr;
  93.     
  94.     if (ref==(ICConfigRefHandle)0)
  95.         return paramErr;
  96.     
  97.     if (GetHandleSize((Handle)ref)<4)
  98.         return paramErr;
  99.     
  100.     if ((*ref)->manufacturer!=kICOurManufacturer)
  101.         return icConfigInappropriateErr;
  102.     
  103.     if (GetHandleSize((Handle)ref)<(sizeof(ICConfigRef)+sizeof(ICFileSpec)))
  104.         return paramErr;
  105.     
  106.     BlockMoveData((Ptr)ref,(Ptr)&filespec,sizeof(ICFileSpecHandle));
  107.     err=HandToHand((Handle*)(&filespec));
  108.     
  109.     if (err==noErr){
  110.         loe=Munger((Handle)filespec,0,(Ptr)0,sizeof(ICConfigRef),&loe,0);
  111.         err=ICFileSpecToFSSpec(filespec,!(flags&icNoUserInteraction_mask),&fs);
  112.         DisposeHandle((Handle)filespec);
  113.     }
  114.     
  115.     if (err==noErr)
  116.         ICRSpecifyConfigFile(inst,&fs);
  117.     
  118.     return err;
  119. }
  120.  
  121. ICError ICRSpecifyConfigFile(ICRRecord* inst,FSSpecPtr config){
  122.     ICError err;
  123.     ICDirSpec folder;
  124.     
  125.     if (inst->perm!=icNoPerm)
  126.         return paramErr;
  127.     
  128.     folder.vRefNum=config->vRefNum;
  129.     folder.dirID=config->parID;
  130.     
  131.     err=ValidDirSpec(&folder);
  132.     
  133.     if (err==noErr)
  134.         BlockMoveData((Ptr)config,(Ptr)&(inst->config_file),sizeof(FSSpec));
  135.     
  136.     inst->have_config_file=(err==noErr);
  137.     
  138.     if (inst->have_config_file){
  139.         // Need to ensure that there is a resource fork for a file...
  140.         err=EnsureResourceFork(&(inst->config_file));
  141.     }
  142.     
  143.     return err;
  144. }
  145.  
  146. ICError ICRGetSeed(ICRRecord* inst,long* seed){
  147.     ICError err;
  148.     CInfoPBRec cpb;
  149.     
  150.     *seed=0L;
  151.     err=fnfErr;
  152.     
  153.     if (inst->have_config_file){
  154.         cpb.hFileInfo.ioVRefNum=inst->config_file.vRefNum;
  155.         cpb.hFileInfo.ioDirID=inst->config_file.parID;
  156.         cpb.hFileInfo.ioNamePtr=inst->config_file.name;
  157.         cpb.hFileInfo.ioFDirIndex=0;
  158.         
  159.         err=PBGetCatInfoSync(&cpb);
  160.         
  161.         if (err==noErr)
  162.             *seed=cpb.hFileInfo.ioFlMdDat;
  163.         else if (err==fnfErr)
  164.             err=noErr;
  165.     }
  166.     
  167.     return err;
  168. }
  169.  
  170. ICError ICRGetPerm(ICRRecord* inst,ICPerm* perm){
  171.     *perm=inst->perm;
  172.     return noErr;
  173. }
  174.  
  175. short ICRPermToFSPerm(ICPerm perm){
  176.     switch (perm){
  177.         case icReadOnlyPerm:
  178.             return fsRdPerm;
  179.             break;
  180.         case icReadWritePerm:
  181.             return fsRdWrPerm;
  182.             break;
  183.         default:
  184.             return 0;
  185.             break;
  186.     }
  187.     
  188.     return 0;
  189. }
  190.  
  191. ICError ICRBegin(ICRRecord* inst,ICPerm perm){
  192.     ICError err;
  193.     short ref;
  194.     
  195.     if ((inst->perm!=icNoPerm)||(perm==icNoPerm))
  196.         return paramErr;
  197.     
  198.     if (!inst->have_config_file)
  199.         return bdNamErr;
  200.     
  201.     ref=FSpOpenResFile(&(inst->config_file),ICRPermToFSPerm(perm));
  202.     err=ResError();
  203.     
  204.     if ((err==fnfErr)||(err==eofErr)){
  205.         switch (perm){
  206.             case icReadOnlyPerm:
  207.                 ref=0;
  208.                 err=noErr;
  209.                 break;
  210.             case icReadWritePerm:
  211.                 FSpCreate(&(inst->config_file),kICCreator,kICFileType,smSystemScript);
  212.                 FSpCreateResFile(&(inst->config_file),kICCreator,kICFileType,smSystemScript);
  213.                 ref=FSpOpenResFile(&(inst->config_file),ICRPermToFSPerm(perm));
  214.                 err=ResError();
  215.                 break;
  216.         }
  217.     }
  218.     
  219.     if (err==noErr){
  220.         inst->config_refnum=ref;
  221.         inst->perm=perm;
  222.     } else {
  223.         if ((err==opWrErr)||(err==permErr)){
  224.             err=icNoMoreWritersErr;
  225.         }
  226.     }
  227.     
  228.     return err;
  229. }
  230.  
  231. ICError ICRCheckInside(ICRRecord* inst){
  232.     
  233.     if (inst->perm==icNoPerm)
  234.         return paramErr;
  235.     
  236.     return noErr;
  237. }
  238.  
  239. ICError ICRForceInside(ICRRecord* inst,ICPerm perm,Boolean* force_info){
  240.     ICError err;
  241.     
  242.     *force_info=false;
  243.     
  244.     if ((inst->perm==perm)||((inst->perm==icReadWritePerm)&&(perm==icReadOnlyPerm)))
  245.         return noErr;
  246.     else if (inst->perm==icNoPerm){
  247.         err=ICRBegin(inst,perm);
  248.         *force_info=(err==noErr);
  249.     } else
  250.         return icPermErr;
  251.     
  252.     return err;
  253. }
  254.  
  255. ICError ICRReleaseInside(ICRRecord* inst,Boolean force_info){
  256.     if (force_info)
  257.         return ICREnd(inst);
  258.     
  259.     return noErr;
  260. }
  261.  
  262. ICError ICRGetPref(ICRRecord* inst,StringPtr key,ICAttr* attr,Ptr buf,long* size){
  263.     ICError err,err2;
  264.     long max_size=*size;
  265.     long true_size;
  266.     short old_refnum;
  267.     Handle prefh;
  268.     Boolean force_info;
  269.     
  270.     *size=0L;
  271.     *attr=ICattr_no_change;
  272.     prefh=(Handle)0;
  273.     
  274.     err=ICRForceInside(inst,icReadOnlyPerm,&force_info);
  275.     
  276.     if ((err==noErr)&&(inst->config_refnum==0)){
  277.         err=icPrefNotFoundErr;
  278.     }
  279.     
  280.     if ((err==noErr)&&((key[0]==0)||((max_size<0)&&(buf!=(Ptr)0))))
  281.         err=paramErr;
  282.     
  283.     if (err==noErr){
  284.         old_refnum=CurResFile();
  285.         UseResFile(inst->config_refnum);
  286.         err=ResError();
  287.         
  288.         if (err==noErr){
  289.             prefh=Get1NamedResource(kRes_Code,key);
  290.             err=ResError();
  291.             
  292.             if (prefh==(Handle)0)
  293.                 err=icPrefNotFoundErr;
  294.             
  295.             if (err==noErr){
  296.                 true_size=GetHandleSize(prefh);
  297.                 if (true_size<4)
  298.                     err=icPrefDataErr;
  299.             }
  300.             
  301.             if (err==noErr){
  302.                 *size=true_size-4;
  303.                 *attr=**((long**)prefh);
  304.                 
  305.                 if ((buf!=(Ptr)0)&&(*size!=0)){
  306.                     if (*size>max_size)
  307.                         err=icTruncatedErr;
  308.                     else
  309.                         max_size=*size;
  310.                     
  311.                     BlockMoveData((Ptr)((*prefh)+sizeof(long)),buf,max_size);
  312.                 }
  313.             }
  314.             UseResFile(old_refnum);
  315.         }
  316.     }
  317.     
  318.     if (prefh!=(Handle)0)
  319.         ReleaseResource(prefh);
  320.     
  321.     err2=ICRReleaseInside(inst,force_info);
  322.     
  323.     if (err==noErr)
  324.         err=err2;
  325.     
  326.     return err;
  327. }
  328.  
  329. ICError ICRSetPref(ICRRecord* inst,StringPtr key,ICAttr attr,Ptr buf,long size){
  330.     ICError err,err2;
  331.     long old_attr;
  332.     short old_refnum;
  333.     Handle prefh;
  334.     short id;
  335.     Boolean force_info;
  336.     
  337.     prefh=(Handle)0;
  338.     if (buf==(Ptr)0)
  339.         size=0;
  340.     
  341.     err=ICRForceInside(inst,icReadWritePerm,&force_info);
  342.     
  343.     if ((err==noErr)&&(inst->perm!=icReadWritePerm))
  344.         err=icPermErr;
  345.     
  346.     if ((err==noErr)&&(inst->config_refnum==0))
  347.         err=icInternalErr;
  348.     
  349.     if ((err==noErr)&&((key[0]==0)||(size<0)))
  350.         err=paramErr;
  351.     
  352.     if (err==noErr){
  353.         old_refnum=CurResFile();
  354.         UseResFile(inst->config_refnum);
  355.         err=ResError();
  356.         if (err==noErr){
  357.             prefh=Get1NamedResource(kRes_Code,key);
  358.             if ((prefh!=(Handle)0)&&(GetHandleSize(prefh)<4)){
  359.                 RmveResource(prefh);
  360.                 DisposeHandle(prefh);
  361.                 prefh=(Handle)0;
  362.             }
  363.             if (prefh==(Handle)0)
  364.                 old_attr=0;
  365.             else
  366.                 old_attr=**((long**)prefh);
  367.             
  368.             if (attr==ICattr_no_change)
  369.                 attr=old_attr;
  370.             
  371.             if ((old_attr&ICattr_locked_mask)&&(attr&ICattr_locked_mask)&&(buf!=(Ptr)0))
  372.                 err=icPermErr;
  373.             
  374.             if (prefh==(Handle)0){
  375.                 prefh=NewHandle(size+4);
  376.                 err=MemError();
  377.                 
  378.                 if (err==noErr){
  379.                     do {
  380.                         id=Unique1ID(kRes_Code);
  381.                     } while (id<=127);
  382.                     
  383.                     AddResource(prefh,kRes_Code,id,key);
  384.                     err=ResError();
  385.                     
  386.                     if (err!=noErr){
  387.                         DisposeHandle(prefh);
  388.                         prefh=(Handle)0;
  389.                     }
  390.                 }
  391.             }
  392.             if ((err==noErr)&&(buf!=(Ptr)0)){
  393.                 SetHandleSize(prefh,size+4);
  394.                 err=MemError();
  395.             }
  396.             if ((err==noErr)&&(size>0))
  397.                 BlockMoveData(buf,(Ptr)((*prefh)+4),size);
  398.             if (err==noErr){
  399.                 **((long**)prefh)=attr;
  400.                 ChangedResource(prefh);
  401.                 WriteResource(prefh);
  402.                 err=ResError();
  403.             }
  404.             UseResFile(old_refnum);
  405.         }
  406.     }
  407.     
  408.     if (prefh!=(Handle)0)
  409.         ReleaseResource(prefh);
  410.     
  411.     err2=ICRReleaseInside(inst,force_info);
  412.     
  413.     if (err==noErr)
  414.         err=err2;
  415.     
  416.     return err;
  417. }
  418.  
  419. // I call ICRForceInside to speed this routine up.  ICRForceInside will do an ICRBegin and hence open the resource
  420. // file, which is good because otherwise I'd open it twice, once for each ICRGetPref.
  421.  
  422. ICError ICRFindPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle prefh){
  423.     ICError err=noErr,err2=noErr;
  424.     long prefsize=0L;
  425.     Boolean force_info;
  426.     
  427.     if (prefh==(Handle)0)
  428.         err=paramErr;
  429.     
  430.     if (err==noErr){
  431.         err=ICRForceInside(inst,icReadOnlyPerm,&force_info);
  432.         if (err==noErr)
  433.             err=ICRGetPref(inst,key,attr,(Ptr)0,&prefsize);
  434.         
  435.         if (err==noErr){
  436.             SetHandleSize(prefh,prefsize);
  437.             err=MemError();
  438.         }
  439.         
  440.         if (err==noErr){
  441.             HLock(prefh);
  442.             err=ICRGetPref(inst,key,attr,*prefh,&prefsize);
  443.             HUnlock(prefh);
  444.         }
  445.         
  446.         err2=ICRReleaseInside(inst,force_info);
  447.     }
  448.     if (err==noErr)
  449.         err=err2;
  450.     
  451.     if ((prefh!=(Handle)0)&&(err!=noErr)){
  452.         SetHandleSize(prefh,0);
  453.     }
  454.     
  455.     return err;
  456. }
  457.  
  458. ICError ICRGetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle* prefh){
  459.     ICError err;
  460.     
  461.     *prefh=NewHandle(0);
  462.     err=MemError();
  463.     
  464.     if (err==noErr)
  465.         err=ICRFindPrefHandle(inst,key,attr,*prefh);
  466.     
  467.     if (err==icPrefNotFoundErr){
  468.         SetHandleSize(*prefh,0);
  469.         *attr=0;
  470.         err=noErr;
  471.     }
  472.     
  473.     return err;
  474. }
  475.  
  476. ICError ICRSetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr attr,Handle prefh){
  477.     ICError err=noErr;
  478.     SignedByte s;
  479.     
  480.     if (prefh!=(Handle)0){
  481.         if (*prefh==(Ptr)0)
  482.             err=paramErr;
  483.         if (err==noErr){
  484.             s=HGetState(prefh);
  485.             HLock(prefh);
  486.             err=ICRSetPref(inst,key,attr,*prefh,GetHandleSize(prefh));
  487.             HSetState(prefh,s);
  488.         }
  489.     } else {
  490.         err=ICRSetPref(inst,key,attr,(Ptr)0,0);
  491.     }
  492.     
  493.     return err;
  494. }
  495.  
  496. ICError ICRCountPref(ICRRecord* inst,long* count){
  497.     ICError err;
  498.     short old_refnum;
  499.     
  500.     err=ICRCheckInside(inst);
  501.     if (err==noErr){
  502.         if (inst->config_refnum==0)
  503.             *count=0;
  504.         else {
  505.             old_refnum=CurResFile();
  506.             UseResFile(inst->config_refnum);
  507.             err=ResError();
  508.             if (err==noErr){
  509.                 *count=Count1Resources(kRes_Code);
  510.                 err=ResError();
  511.                 UseResFile(old_refnum);
  512.             }
  513.         }
  514.     }
  515.     
  516.     if (err!=noErr)
  517.         *count=0;
  518.     
  519.     return err;
  520. }
  521.  
  522. ICError ICRGetIndPref(ICRRecord* inst,long n,StringPtr key){
  523.     ICError err;
  524.     short old_refnum;
  525.     Handle prefh=(Handle)0;
  526.     short junk_id;
  527.     ResType junk_type;
  528.     
  529.     err=ICRCheckInside(inst);
  530.     if ((err==noErr)&&(n<1))
  531.         err=paramErr;
  532.     
  533.     if (err==noErr){
  534.         if (inst->config_refnum==0)
  535.             err=icPrefNotFoundErr;
  536.         else {
  537.             old_refnum=CurResFile();
  538.             UseResFile(inst->config_refnum);
  539.             err=ResError();
  540.             if (err==noErr){
  541.                 SetResLoad(false);
  542.                 prefh=Get1IndResource(kRes_Code,n);
  543.                 SetResLoad(true);
  544.                 
  545.                 if (prefh==(Handle)0)
  546.                     err=icPrefNotFoundErr;
  547.                 else {
  548.                     GetResInfo(prefh,&junk_id,&junk_type,key);
  549.                     err=ResError();
  550.                 }
  551.                 UseResFile(old_refnum);
  552.             }
  553.         }
  554.     }
  555.     
  556.     if (prefh!=(Handle)0)
  557.         ReleaseResource(prefh);
  558.     
  559.     return err;
  560. }
  561.  
  562. ICError ICRDeletePref(ICRRecord* inst,StringPtr key){
  563.     ICError err;
  564.     Handle prefh;
  565.     short old_refnum;
  566.     
  567.     err=ICRCheckInside(inst);
  568.     if ((err==noErr)&&(key[0]==0))
  569.         err=paramErr;
  570.     
  571.     if (err==noErr){
  572.         if (inst->config_refnum==0)
  573.             err=icPrefNotFoundErr;
  574.         else {
  575.             old_refnum=CurResFile();
  576.             UseResFile(inst->config_refnum);
  577.             err=ResError();
  578.             if (err==noErr){
  579.                 SetResLoad(false);
  580.                 prefh=Get1NamedResource(kRes_Code,key);
  581.                 err=ResError();
  582.                 SetResLoad(true);
  583.                 if (prefh==(Handle)0)
  584.                     err=icPrefNotFoundErr;
  585.                 else {
  586.                     RmveResource(prefh);
  587.                     DisposeHandle(prefh);
  588.                     err=ResError();
  589.                 }
  590.                 UseResFile(old_refnum);
  591.             }
  592.         }
  593.     }
  594.     
  595.     return err;
  596. }
  597.  
  598. ICError ICREnd(ICRRecord* inst){
  599.     ICError err;
  600.     
  601.     err=ICRCheckInside(inst);
  602.     ICRCloseIfOpen(inst);
  603.     
  604.     return err;
  605. }
  606.  
  607. ICError ICRDefaultFileName(ICRRecord* inst,StringPtr name){
  608.     Str63 lname=kICDefaultFileName;
  609.     
  610.     BlockMoveData(lname,name,lname[0]+1);
  611.     
  612.     return noErr;
  613. }
  614.  
  615. ICError ICREditPreferences(ICRRecord* inst,StringPtr key){
  616.     ICError err;
  617.     
  618.     if (!inst->have_config_file)
  619.         return bdNamErr;
  620.     
  621.     return EditPreferences(key,&(inst->config_file));
  622. }
  623.  
  624. /*
  625.     URL Parsing Algorithm
  626.  
  627.     1. if there is a selection skip to step 4
  628.     2. expand selection to end of word (never skip an angle bracket though)
  629.     3. if either end has an angle bracket then expand other end to search for angle bracket
  630.     4. strip trailing and leading whitespace
  631.     5. strip whitespace CR whitespace
  632.     6. off < > if necessary
  633.     7. remove leading URL:
  634.     8. extract protocol by looking forwards for :
  635.     9. if no protocol then prepend "hint:"
  636. */
  637.  
  638. Boolean __URL_SpecStartChar(char ch){
  639.     switch (ch){
  640.         case ' ':
  641.         case '<':
  642.         case 9:
  643.         case 13:
  644.             return true;
  645.         default:
  646.             return false;
  647.     }
  648. }
  649.  
  650. Boolean __URL_SpecEndChar(char ch){
  651.     switch (ch){
  652.         case ' ':
  653.         case '>':
  654.         case 9:
  655.         case 13:
  656.             return true;
  657.         default:
  658.             return false;
  659.     }
  660. }
  661.  
  662. ICError ExpandSelection(char* datap,long len,long* selStart,long* selEnd){
  663.     ICError err=noErr;
  664.     Boolean found;
  665.     
  666.     // expand leading selection backwards looking for word break
  667.     while ((*selStart>0)&&(!__URL_SpecStartChar(datap[(*selStart)-1])))
  668.         (*selStart)--;
  669.     if ((*selStart>0)&&(datap[(*selStart)-1]=='<'))
  670.         (*selStart)--;
  671.     
  672.     // expand trailing selection forwards looking for word break
  673.     while ((*selEnd<len)&&(!__URL_SpecEndChar(datap[*selEnd])))
  674.         (*selEnd)++;
  675.     if ((*selEnd<len)&&(datap[*selEnd]=='>'))
  676.         (*selEnd)++;
  677.     
  678.     // if first char was a < then expand trailing selection to meet matching >
  679.     if ((datap[*selStart]=='<')&&(datap[(*selEnd)-1]!='>')){
  680.         while ((datap[(*selEnd)-1]!='>')&&((*selEnd)-1<=len))
  681.             (*selEnd)++;
  682.         
  683.         // now either a match or at end of len
  684.         if (datap[(*selEnd)-1]!='>')
  685.             return icNoURLErr;
  686.     }
  687.     
  688.     // if last char was a > then expand leading selection to meet matching <
  689.     if ((datap[*selEnd]=='>')&&(datap[*selStart]!='<')){
  690.         while ((datap[*selStart]!='<')&&(*selStart>=0))
  691.             (*selStart)--;
  692.         
  693.         // now either a match or at end of len
  694.         if (datap[*selStart]!='<')
  695.             return icNoURLErr;
  696.     }
  697.     
  698.     return err;
  699. }
  700.  
  701. Boolean SpaceTab(char ch){
  702.     if ((ch==' ')||(ch==9))
  703.         return true;
  704.     return false;
  705. }
  706.  
  707. Boolean SpaceTabRet(char ch){
  708.     if (ch==13)
  709.         return true;
  710.     return SpaceTab(ch);
  711. }
  712.  
  713. ICError ShrinkSelection(char* datap,long len,long* selStart,long* selEnd){
  714.     if (SpaceTab(datap[*selStart]))
  715.         while (SpaceTab(datap[*selStart]))
  716.             (*selStart)++;
  717.     if (SpaceTab(datap[(*selEnd)-1]))
  718.         while (SpaceTab(datap[(*selEnd)-1]))
  719.             (*selEnd)--;
  720.     
  721.     return noErr;
  722. }
  723.  
  724. ICError StripReturns(Handle urlh){
  725.     ICError err;
  726.     long srcsize,srcndx,dstndx;
  727.     char* buf;
  728.     SignedByte s;
  729.     
  730.     srcsize=GetHandleSize(urlh);
  731.     err=MemError();
  732.     if (srcsize==0){
  733.         if (err!=noErr)
  734.             return err;
  735.         
  736.         return icNoURLErr;
  737.     }
  738.     
  739.     srcndx=0;
  740.     dstndx=0;
  741.     
  742.     s=HGetState(urlh);
  743.     HLock(urlh);
  744.     buf=(char*)(*urlh);
  745.     
  746.     // skip down the buffer copying src to dst except when meeting cr
  747.     while (srcndx<srcsize){
  748.         if (buf[srcndx]==13){
  749.             // move dstndx back to point to previous non-whitespace
  750.             while ((dstndx>0)&&(SpaceTab(buf[dstndx-1])))
  751.                 dstndx--;
  752.             // move srcndx forwards to next non-whitespace
  753.             while ((srcndx<srcsize)&&(SpaceTabRet(buf[srcndx])))
  754.                 srcndx++;
  755.         }
  756.         
  757.         if (srcndx<srcsize){
  758.             // copy byte from src to dest
  759.             buf[dstndx]=buf[srcndx];
  760.             srcndx++;
  761.             dstndx++;
  762.         }
  763.     }
  764.     
  765.     HSetState(urlh,s);
  766.     
  767.     // resize the handle to the number of bytes that we copied
  768.     SetHandleSize(urlh,dstndx);
  769.     err=MemError();
  770.     
  771.     return err;
  772. }
  773.  
  774. ICError ICRParseURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd,Handle urlh){
  775.     char* datap=(char*)data;
  776.     Str31 tmp="\pURL:";
  777.     long junklong;
  778.     long ndx;
  779.     ICError err=noErr;
  780.     
  781.     if ((data==(Ptr)0)||(urlh==(Handle)0)||(*urlh==(Ptr)0)||(len<=0)||(*selStart<0)||(*selEnd<0)||(*selStart>len)||(*selEnd>len)||(*selStart>*selEnd))
  782.         return paramErr;
  783.     
  784.     if (*selStart==*selEnd)
  785.         err=ExpandSelection(datap,len,selStart,selEnd);
  786.     if (err==noErr) // remove leading and trailing whitespace
  787.         err=ShrinkSelection(datap,len,selStart,selEnd);
  788.     
  789.     if ((err==noErr)&&(*selStart>=*selEnd))
  790.         return icNoURLErr;
  791.     
  792.     err=PtrToXHand((Ptr)&(datap[*selStart]),urlh,(*selEnd)-(*selStart));
  793.     if (err==noErr)
  794.         err=StripReturns(urlh);
  795.     
  796.     if (err==noErr){
  797.         // strip any enclosing < >
  798.         char* buf;
  799.         long bsize=GetHandleSize(urlh);
  800.         SignedByte s=HGetState(urlh);
  801.         Boolean doTrim=false;
  802.         
  803.         HLock(urlh);
  804.         buf=(char*)(*urlh);
  805.         
  806.         if ((buf[0]=='<')&&(buf[bsize-1]=='>')){
  807.             doTrim=true;
  808.         }
  809.         
  810.         HSetState(urlh,s);
  811.         
  812.         if (doTrim){
  813.             SetHandleSize(urlh,bsize-1);
  814.             HUnlock(urlh);
  815.             // unlock before the munger call
  816.             Munger(urlh,0,(Ptr)0,1,(Ptr)-1,0);
  817.             HSetState(urlh,s);
  818.         }
  819.         
  820.         // trim off leading "\pURL:"
  821.         HLock(urlh);
  822.         if ((GetHandleSize(urlh)>tmp[0])&&(IUMagIDString(*urlh,&(tmp[1]),tmp[0],tmp[0])==0)){
  823.             HUnlock(urlh);
  824.             Munger(urlh,0,(Ptr)0,tmp[0],(Ptr)-1,0);
  825.         }
  826.         HSetState(urlh,s);
  827.         
  828.         // search for protocol
  829.         tmp[0]=1;tmp[1]=':';
  830.         HUnlock(urlh);
  831.         ndx=Munger(urlh,0,&(tmp[1]),1,(Ptr)0,0);
  832.         if ((ndx<0)||(ndx>255)){
  833.             // failed to find a colon in first 256 bytes,prepend "hint:" to url
  834.             if (hint[0]==0)
  835.                 err=icNoURLErr;
  836.             else {
  837.                 Munger(urlh,0,(Ptr)0,0,&(hint[1]),hint[0]);
  838.                 err=MemError();
  839.             }
  840.         }
  841.         HSetState(urlh,s);
  842.     }
  843.     return err;
  844. }
  845.  
  846. ICError ICRLaunchURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd){
  847.     ICError err;
  848.     Handle urlh;
  849.     ICAppSpec helper;
  850.     Str255 scheme;
  851.     Str255 temp=kICHelper;
  852.     long junk_attr;
  853.     long size;
  854.     
  855.     urlh=NewHandle(0);
  856.     err=MemError();
  857.     
  858.     if (err==noErr)
  859.         err=ICRParseURL(inst,hint,data,len,selStart,selEnd,urlh);
  860.     else 
  861.         urlh=(Handle)0;
  862.     
  863.     if (err==noErr)
  864.         err=FindScheme(urlh,scheme);
  865.     
  866.     if (err==noErr){
  867.         size=sizeof(ICAppSpec);
  868.         BlockMoveData(scheme,(Ptr)&(temp[temp[0]+1]),scheme[0]);
  869.         temp[0]+=scheme[0];
  870.         err=ICRGetPref(inst,temp,&junk_attr,(Ptr)(&helper),&size);
  871.     }
  872.     
  873.     if (err==noErr)
  874.         err=LaunchURL(helper.fCreator,urlh);
  875.     
  876.     if (urlh!=(Handle)0)
  877.         DisposeHandle(urlh);
  878.     
  879.     return err;
  880. }
  881.  
  882. void UnpackCopyString(Ptr* p,StringPtr s){
  883.     short len;
  884.     
  885.     // calc the len of the current pascal string pointed to by p
  886.     len=((**p) & 0x00ff) +1;
  887.     
  888.     // copy the string in the buffer to s
  889.     BlockMoveData(*p,s,len);
  890.     
  891.     // move the pointer to the start of the next pascal string
  892.     *p=(Ptr)((*p)+len);
  893. }
  894.  
  895. // Internal Mapping Subs
  896. OSErr UnpackEntry(Handle entries,long pos,ICMapEntry* entry,long* user_length){
  897.     // WARNING: Depends very much on the exact format of ICMapEntry!
  898.     Ptr org,p;
  899.     long maxsize;
  900.     OSErr err=noErr;
  901.     
  902.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  903.         return paramErr;
  904.     
  905.     p=(Ptr)((*entries)+pos);
  906.     maxsize=GetHandleSize(entries);
  907.     org=p;
  908.     
  909.     BlockMoveData(p,(Ptr)entry,6);
  910.     
  911.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  912.         return badExtResource;
  913.     
  914.     BlockMoveData(p,entry,entry->fixed_length);
  915.     p=(Ptr)(p+entry->fixed_length);
  916.     UnpackCopyString(&p,entry->extension);
  917.     UnpackCopyString(&p,entry->creator_app_name);
  918.     UnpackCopyString(&p,entry->post_app_name);
  919.     UnpackCopyString(&p,entry->MIME_type);
  920.     UnpackCopyString(&p,entry->entry_name);
  921.     
  922.     *user_length=entry->total_length-(p-org);
  923.     
  924.     return err;
  925. }
  926.  
  927. // a fast version of ICRGetEntry doesn't return all of the strings for the entry
  928. // WARNING: Depends very much on the exact format of ICMapEntry!
  929. OSErr FastGetEntry(Handle entries,long pos,ICMapEntry* entry){
  930.     Ptr org,p;
  931.     long maxsize;
  932.     OSErr err=noErr;
  933.     
  934.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  935.         return paramErr;
  936.     
  937.     p=(Ptr)((*entries)+pos);
  938.     maxsize=GetHandleSize(entries);
  939.     BlockMoveData(p,entry,6);
  940.     
  941.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  942.         return badExtResource;
  943.     
  944.     BlockMoveData(p,entry,entry->fixed_length);
  945.     p=(Ptr)(p+entry->fixed_length);
  946.     BlockMoveData(p,entry->extension,(((*p)&0x00ff)+1));
  947.     return err;
  948. }
  949.  
  950. void PackCopyString(ICMapEntry* entry,Ptr p,StringPtr s){
  951.     
  952.     BlockMoveData(s,(Ptr)(p+entry->total_length),s[0]+1);
  953.     entry->total_length+=s[0]+1;
  954. }
  955.  
  956. void PackEntry(ICMapEntry* entry,Ptr p,long user_length){
  957.     Ptr a,b;
  958.     
  959.     entry->version=0;
  960.     
  961.     a=(Ptr)&(entry->extension);
  962.     b=(Ptr)entry;
  963.     
  964.     entry->fixed_length=a-b;
  965.     entry->total_length=entry->fixed_length;
  966.     
  967.     PackCopyString(entry,p,entry->extension);
  968.     PackCopyString(entry,p,entry->creator_app_name);
  969.     PackCopyString(entry,p,entry->post_app_name);
  970.     PackCopyString(entry,p,entry->MIME_type);
  971.     PackCopyString(entry,p,entry->entry_name);
  972.     
  973.     entry->total_length+=user_length;
  974.     
  975.     BlockMoveData(entry,p,entry->fixed_length);
  976. }
  977.  
  978. short GetShort(Ptr P){
  979.     unsigned char* p=(unsigned char*)P;
  980.     short val=0;
  981.     
  982.     val=p[0];
  983.     val <<= 8;
  984.     val+=p[1];
  985.     
  986.     return val;
  987. }
  988.  
  989. char UpCase(char ch){
  990.     
  991.     if ((ch>='a')&&(ch<='z'))
  992.         return (ch-'a')+'A';
  993.     
  994.     return ch;
  995. }
  996.  
  997. Boolean IsExtensionVar(StringPtr name,StringPtr ext){
  998.     short pn,pe;
  999.     
  1000.     if (name[0]>=ext[0]){
  1001.         pn=name[0]-ext[0]+1;
  1002.         pe=1;
  1003.         
  1004.         while (pe<=ext[0]){
  1005.             if (UpCase(name[pn])!=UpCase(ext[pe]))
  1006.                 break;
  1007.             
  1008.             pn++;
  1009.             pe++;
  1010.         }
  1011.         
  1012.         return pe>ext[0];
  1013.     }
  1014.     return false;
  1015. }
  1016.  
  1017. // Low Level Mapping Routines
  1018.  
  1019. ICError ICRCountMapEntries(ICRRecord* inst,Handle entries,long* count){
  1020.     Ptr p;
  1021.     long pos;
  1022.     short size;
  1023.     long hsize;
  1024.     
  1025.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1026.         return paramErr;
  1027.     
  1028.     p=*entries;
  1029.     pos=0L;
  1030.     *count=0;
  1031.     hsize=GetHandleSize(entries);
  1032.     while (pos<hsize){
  1033.         size=GetShort(p); // extract the total_length value from the current pointer
  1034.         pos+=size; // add it to the pos offset
  1035.         p+=size; // add it to the pointer
  1036.         (*count)++; // increment the count
  1037.     }
  1038.     
  1039.     return noErr;
  1040. }
  1041.  
  1042. ICError ICRGetIndMapEntry(ICRRecord* inst,Handle entries,long ndx,long* pos,ICMapEntry* entry){
  1043.     ICError err;
  1044.     Ptr p;
  1045.     long i;
  1046.     short size;
  1047.     long hsize;
  1048.     
  1049.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(ndx<0))
  1050.         return paramErr;
  1051.     
  1052.     p=(Ptr)*entries;
  1053.     *pos=0;
  1054.     hsize=GetHandleSize(entries);
  1055.     
  1056.     while ((ndx>1)&&(*pos<hsize)){
  1057.         size=GetShort(p); // extract the total_length value from the current pointer
  1058.         *pos+=size; // add the size to the pos offset
  1059.         p+=size; // add the size to the pointer
  1060.         ndx--; // decrease the index for the entry
  1061.     }
  1062.     
  1063.     return ICRGetMapEntry(inst,entries,*pos,entry);
  1064. }
  1065.  
  1066. ICError ICRGetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  1067.     ICError err;
  1068.     long user_length;
  1069.     
  1070.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  1071.         return paramErr;
  1072.     
  1073.     return UnpackEntry(entries,pos,entry,&user_length);
  1074. }
  1075.  
  1076. ICError ICRSetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  1077.     ICError err;
  1078.     ICMapEntry e,oldentry;
  1079.     long user_length,source_length;
  1080.     
  1081.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  1082.         return paramErr;
  1083.     
  1084.     err=UnpackEntry(entries,pos,&oldentry,&user_length);
  1085.     
  1086.     if (err==noErr){
  1087.         PackEntry(entry,(Ptr)&e,user_length);
  1088.         source_length=oldentry.total_length-user_length;
  1089.         
  1090.         if (user_length<8){ // hack to remove alignment bytes from previous version
  1091.             source_length=oldentry.total_length;
  1092.             e.total_length=e.total_length-user_length;
  1093.             user_length=0;
  1094.         }
  1095.         Munger(entries,pos,(Ptr)0,source_length,&e,e.total_length-user_length);
  1096.         err=MemError();
  1097.     }
  1098.     
  1099.     return err;
  1100. }
  1101.  
  1102. ICError ICRDeleteMapEntry(ICRRecord* inst,Handle entries,long pos){
  1103.     ICError err;
  1104.     ICMapEntry entry;
  1105.     long user_length;
  1106.     
  1107.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>=GetHandleSize(entries)))
  1108.         return paramErr;
  1109.     
  1110.     err=UnpackEntry(entries,pos,&entry,&user_length);
  1111.     
  1112.     if (err==noErr){
  1113.         Munger(entries,pos,(Ptr)0,entry.total_length,(Ptr)-1,0);
  1114.         err=MemError();
  1115.     }
  1116.     
  1117.     return err;
  1118. }
  1119.  
  1120. ICError ICRAddMapEntry(ICRRecord* inst,Handle entries,ICMapEntry* entry){
  1121.     ICError err;
  1122.     ICMapEntry tmp_entry;
  1123.     
  1124.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1125.         return paramErr;
  1126.     
  1127.     PackEntry(entry,(Ptr)&tmp_entry,0);
  1128.     
  1129.     return PtrAndHand(&tmp_entry,entries,entry->total_length);
  1130. }
  1131.  
  1132. // High Level Mapping Subs
  1133.  
  1134. ICError ICRMapEntriesFilename(ICRRecord* inst,Handle entries,StringPtr filename,ICMapEntry* entry){
  1135.     // Implementation lifted directly from Space Aliens
  1136.     ICError err;
  1137.     short longest_len;
  1138.     long posndx,found_pos;
  1139.     
  1140.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(filename[0]==0))
  1141.         return paramErr;
  1142.     
  1143.     // loop through the entries
  1144.     // looking for the longest match
  1145.     
  1146.     longest_len=0;
  1147.     posndx=0;
  1148.     
  1149.     while (FastGetEntry(entries,posndx,entry)==noErr){
  1150.         // the entry matches if not_incoming flag bit is clear,
  1151.         // it's longer than the previous match, it's longer than the filename,
  1152.         // and it matches the last N chars of the filename.
  1153.         
  1154.         if ((entry->extension[0]>longest_len)&&(!(entry->flags&ICmap_not_incoming_mask))&&(IsExtensionVar(filename,entry->extension))){
  1155.             // record the new longest entry
  1156.             found_pos=posndx;
  1157.             longest_len=entry->extension[0];
  1158.         }
  1159.         // increment posndx so that we get the next entry the next time around the loop
  1160.         posndx+=entry->total_length;
  1161.     }
  1162.     
  1163.     if (longest_len==0)
  1164.         return icPrefNotFoundErr;
  1165.     
  1166.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  1167. }
  1168.  
  1169. ICError ICRMapEntriesTypeCreator(ICRRecord* inst,Handle entries,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  1170.     ICError err;
  1171.     long posndx,found_pos,match_weight,best_weight;
  1172.     
  1173.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1174.         return paramErr;
  1175.     
  1176.     posndx=0L;
  1177.     best_weight=-1L;
  1178.     
  1179.     while (FastGetEntry(entries,posndx,entry)==noErr){
  1180.         if (!(entry->flags&ICmap_not_outgoing_mask)){
  1181.             if (entry->file_type==fType){
  1182.                 match_weight=entry->file_creator==fCreator;
  1183.                 if (IsExtensionVar(filename,entry->extension)){
  1184.                     match_weight+=2*(entry->extension[0]);
  1185.                 }
  1186.                 if (match_weight>best_weight){
  1187.                     // record the new longest entry
  1188.                     found_pos=posndx;
  1189.                     best_weight=match_weight;
  1190.                 }
  1191.             }
  1192.         }
  1193.         posndx+=entry->total_length;
  1194.     }
  1195.     
  1196.     if (best_weight==-1)
  1197.         return icPrefNotFoundErr;
  1198.     
  1199.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  1200. }
  1201.  
  1202. // High Level Mapping Routines
  1203.  
  1204. ICError ICRMapFilename(ICRRecord* inst,StringPtr filename,ICMapEntry* entry){
  1205.     ICError err;
  1206.     Handle entries;
  1207.     ICAttr junk_attr;
  1208.     
  1209.     if (filename[0]==0)
  1210.         return paramErr;
  1211.     
  1212.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  1213.     if (err==noErr){
  1214.         err=ICRMapEntriesFilename(inst,entries,filename,entry);
  1215.         DisposeHandle(entries);
  1216.     }
  1217.     
  1218.     return err;
  1219. }
  1220.  
  1221. ICError ICRMapTypeCreator(ICRRecord* inst,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  1222.     ICError err;
  1223.     Handle entries;
  1224.     ICAttr junk_attr;
  1225.     
  1226.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  1227.     if (err==noErr){
  1228.         err=ICRMapEntriesTypeCreator(inst,entries,fType,fCreator,filename,entry);
  1229.         DisposeHandle(entries);
  1230.     }
  1231.     
  1232.     return err;
  1233. }
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.